import { Kline, Indicator, Quant } from "../lib/quant";
import { Slope } from "../lib/quant/indicator/slope";
import { MA } from "../lib/quant/indicator/ma";
import { Statistics } from "./indicators/statistics";
import { keepDecimalFixed } from "../utils";
import { Pipeline, PipelineMiddleware } from "../common/Pipeline";



export interface PipelineIndicatorContext {
    quant: Quant<Kline>;
    indicators: Map<string, Indicator>;
    bar: Kline;
    customIndicators?: {
      change_rate: number;
      close_ma_rate: number;
      volume_rate: number;
      sell_rate: number;
    }
}
export const before: PipelineMiddleware<PipelineIndicatorContext> = (ctx, next) => {
    if (ctx.customIndicators === undefined) {
        ctx.customIndicators = {} as PipelineIndicatorContext['customIndicators']
    }
    next()
}

/**
 * 涨幅变化
 */
export const changeRateMiddleware: PipelineMiddleware<PipelineIndicatorContext> = (ctx, next) => {
    const { quant, bar, indicators } = ctx;
    if (quant.history.get(quant.history.size() - 2)) {
        const preBar = quant.history.get(quant.history.size() - 2);
        const currentBar = quant.currentData;
        ctx.customIndicators.change_rate = keepDecimalFixed(
            currentBar.close > preBar.close ? (currentBar.high - preBar.low) / preBar.low : (currentBar.low - preBar.high) / preBar.high,
            5
        );
    }
    next()
}

/**
 * close / ma
 */
export const closeMARateMiddleware: PipelineMiddleware<PipelineIndicatorContext> = (ctx, next) => {
    const { quant, indicators } = ctx
    const ma = (indicators.get('ma240') as MA) || (indicators.get('ma120') as MA) || (indicators.get('ma60') as MA);
    const ma_value = ma.getValue();
    const currentBar = quant.currentData;
    if (!currentBar) {
        ctx.customIndicators.close_ma_rate = 0;
        next();
        return
    }
    ctx.customIndicators.close_ma_rate = keepDecimalFixed((currentBar.close - ma_value) / ma_value, 4);
    next()
}
/**
 * max_volume / 2
 */
export const volumRateMiddleware: PipelineMiddleware<PipelineIndicatorContext> = (ctx, next) => {
    const { quant, bar, indicators } = ctx
    const statistics = (indicators.get('statistics') as Statistics);
    const currentBar = quant.currentData;
    if (!currentBar) {
        ctx.customIndicators.volume_rate = 0;
        next();
        return
    }
    const sum = currentBar.buy + currentBar.sell;
    const volume = currentBar.volume < sum ? sum : currentBar.volume;
    ctx.customIndicators.volume_rate = keepDecimalFixed( volume / statistics.getValue().max_volume, 4);
    next()
}


/**
 * quant_15m.currentData.sell / (quant_15m.currentData.buy + quant_15m.currentData.sell)
 */
export const sellRate: PipelineMiddleware<PipelineIndicatorContext> = (ctx, next) => {
    const { quant, bar, indicators } = ctx

    const currentBar = quant.currentData;
    if (!currentBar) {
        ctx.customIndicators.sell_rate = 0.5;
        next();
        return
    }
    const rate = currentBar.sell / (currentBar.volume)
    ctx.customIndicators.sell_rate = (isNaN(rate) || currentBar.sell === 0) ? 0.5 : keepDecimalFixed(rate, 3);
    next()
}

export const strategyPiepline = new Pipeline<PipelineIndicatorContext>;
strategyPiepline.use(before);
strategyPiepline.use(changeRateMiddleware);
strategyPiepline.use(closeMARateMiddleware);
strategyPiepline.use(volumRateMiddleware);
strategyPiepline.use(sellRate);
